package com.qijian.flowable.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qijian.common.annotation.PlugAnn;
import com.qijian.common.annotation.PlugParam;
import com.qijian.common.core.domain.AjaxResult;
import com.qijian.common.core.domain.entity.FlowablModelApproval;
import com.qijian.common.enums.ApprovalDescriptionEnum;
import com.qijian.common.enums.FlowableCodeEnum;
import com.qijian.common.exception.ServiceException;
import com.qijian.common.utils.SecurityUtils;
import com.qijian.common.utils.StringUtils;
import com.qijian.common.utils.bean.BeanUtils;
import com.qijian.common.utils.uuid.IdUtils;
import com.qijian.flowable.domain.Flow;
import com.qijian.flowable.domain.FlowDetail;
import com.qijian.flowable.domain.FlowDto;
import com.qijian.flowable.domain.query.FlowQuery;
import com.qijian.flowable.domain.vo.FlowCheck;
import com.qijian.flowable.domain.vo.FlowDetailVo;
import com.qijian.flowable.domain.vo.FlowVo;
import com.qijian.flowable.mapper.FlowDetailMapper;
import com.qijian.flowable.mapper.FlowMapper;
import com.qijian.flowable.service.IFlowService;
import com.qijian.system.service.ISysDictDataService;
import com.qijian.tool.service.IStorageService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static com.qijian.common.core.controller.BaseController.cleanDetailsData;

/**
 * 流程Service业务层处理
 *
 * @author qijian
 * @date 2024-03-01
 */
@Service
@RequiredArgsConstructor
public class FlowServiceImpl extends ServiceImpl<FlowMapper, Flow> implements IFlowService {

    private final FlowMapper flowMapper;

    private final FlowDetailMapper flowDetailMapper;


    private final ISysDictDataService sysDictDataService;

    private final IStorageService storageService;



    @Override
    public void saveFlow(FlowVo flowVo) {
        Map<String, String> dataByDictType = sysDictDataService.getDataByDictType("equipment_ledger_dept");
        String deptName = SecurityUtils.getLoginUser().getUser().getDept().getFactoryName();
        if (dataByDictType != null && deptName != null) {
            flowVo.setDeptName(deptName);
            flowVo.setDeptId(dataByDictType.get(deptName) != null ? Long.parseLong(dataByDictType.get(deptName)) : null);
        }
        if (flowVo.getMainFlowType().equals("flow_re_eq")
                || flowVo.getMainFlowType().equals("flow_re_gz")
                || flowVo.getMainFlowType().startsWith("flow_re_bf")
        ) {
            flowVo.setFlowType("flow_re");
        } else if (flowVo.getMainFlowType().equals("flow_re_eq_c")
                || flowVo.getMainFlowType().equals("flow_re_gz_c")
        ) {
            flowVo.setFlowType("flow_re_c");
        }
        // flowVo.getAction() ： 1 新增 2 修改 2 报废
        flowVo.setCode(IdUtils.getNumber(FlowableCodeEnum.valueOf(flowVo.getMainFlowType()).getValue() + "-", flowMapper.countCurrentDateWithDel() + 1));
        String flowType = flowVo.getMainFlowType().split("_")[0] + "_" + flowVo.getMainFlowType().split("_")[1] + "_" + flowVo.getMainFlowType().split("_")[2];
        if ("1".equals(flowVo.getAction())) {
            //1.校验提交参数
            if (CollectionUtils.isNotEmpty(flowVo.getDetails().stream().map(e -> e.getSourceId()).collect(Collectors.toList()))) {
                List<FlowDetail> list = flowMapper.countFlowByConditon(flowType, flowVo.getDetails().stream().map(e -> e.getSourceId()).collect(Collectors.toList()));
                if (CollectionUtils.isNotEmpty(list)) {
                    throw new ServiceException("存在冲突，单据审核中");
                }
            }
            // 保存单据
            flowVo.setApprovalStatus(ApprovalDescriptionEnum.B);
            flowVo.setApprovalTime(new Date());
            flowVo.setCreateById(SecurityUtils.getUserId());
            this.save(flowVo);
            flowVo.getDetails().forEach(e -> {
                e.setMainId(flowVo.getId());
                e.setClassType(FlowableCodeEnum.valueOf(flowVo.getMainFlowType()).getClassType());
                flowDetailMapper.insert(e);
            });


        } else if ("2".equals(flowVo.getAction())) {
            if (ObjectUtil.isNull(flowVo)) {
                throw new ServiceException("单据信息错误！");
            }
            ApprovalDescriptionEnum approval = (ApprovalDescriptionEnum) ReflectUtil.getFieldValue(flowVo, "approvalStatus");
            if (approval == ApprovalDescriptionEnum.B) {
                throw new ServiceException("单据审核中！");
            } else if (approval == ApprovalDescriptionEnum.C) {
                throw new ServiceException("单据已审核！");
            }
            List<Long> ids = flowVo.getDetails().stream().map(e -> e.getId()).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(ids)) {
                throw new ServiceException("数据异常");
            }
            List<FlowDetail> list = flowMapper.countFlowByConditon(flowType, flowVo.getDetails().stream().map(e -> e.getSourceId()).collect(Collectors.toList()));
            if (CollectionUtils.isNotEmpty(list)) {
                throw new ServiceException("存在冲突，单据审核中，或已审核");
            }
            flowVo.setCreateById(SecurityUtils.getUserId());
            // 保存单据
            flowVo.setApprovalStatus(ApprovalDescriptionEnum.B);
            flowVo.setApprovalTime(new Date());
            this.save(flowVo);
            flowVo.getDetails().forEach(e -> {
                e.setMainId(flowVo.getId());
                e.setClassType(FlowableCodeEnum.valueOf(flowVo.getMainFlowType()).getClassType());
                flowDetailMapper.insert(e);
            });

        } else if ("3".equals(flowVo.getAction())) {
            if (ObjectUtil.isNull(flowVo)) {
                throw new ServiceException("单据信息错误！");
            }
            ApprovalDescriptionEnum approval = (ApprovalDescriptionEnum) ReflectUtil.getFieldValue(flowVo, "approvalStatus");
            if (approval == ApprovalDescriptionEnum.B) {
                throw new ServiceException("单据审核中！");
            } else if (approval == ApprovalDescriptionEnum.C) {
                throw new ServiceException("单据已审核！");
            }
            List<Long> souceIds = flowVo.getDetails().stream().map(e -> e.getSourceId()).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(souceIds)) {
                throw new ServiceException("数据异常");
            }
            List<FlowDetail> list = flowMapper.countFlowByConditon(flowType, flowVo.getDetails().stream().map(e -> e.getSourceId()).collect(Collectors.toList()));
            if (CollectionUtils.isNotEmpty(list)) {
                throw new ServiceException("存在冲突，单据审核中");
            }
            // 保存单据
            flowVo.setApprovalStatus(ApprovalDescriptionEnum.B);
            flowVo.setApprovalTime(new Date());
            flowVo.setCreateById(SecurityUtils.getUserId());
            this.save(flowVo);
            flowVo.getDetails().forEach(e -> {
                e.setMainId(flowVo.getId());
                e.setClassType(FlowableCodeEnum.valueOf(flowVo.getMainFlowType()).getClassType());
                flowDetailMapper.insert(e);
            });

        }

    }

    @Override
    public FlowVo getInfoById(Long id) {
        FlowVo info = this.getBaseMapper().getInfoById(id);
        if (Objects.isNull(info)) {
            return info;
        }
        if (CollectionUtils.isNotEmpty(info.getFlowList())) {
            info.setFlowList(Arrays.asList(info.getFlowList().get(0)));
        }

        return info;
    }

    @Override
    public List<FlowDetailVo> getKnifeInfoById(Long id) {
        List<FlowDetailVo> list = new ArrayList<>();
        FlowVo flowVo = this.getBaseMapper().getInfoById(id);
        if (flowVo != null) {
            if (CollectionUtils.isNotEmpty(flowVo.getDetails())) {
                flowVo.getDetails().forEach(e -> {
                    FlowDetailVo flowDetailVo = new FlowDetailVo();
                    BeanUtils.copyProperties(e, flowDetailVo);
                    FlowDto dto = JSONUtil.toBean(e.getExtra(), FlowDto.class);
                    flowDetailVo.setSpec(dto.getSpec());
                    flowDetailVo.setName(dto.getName());
                    flowDetailVo.setCode(dto.getCode());
                    flowDetailVo.setNumber(dto.getNumber());
                    flowDetailVo.setUnit(dto.getUnit());
                    flowDetailVo.setBrand(dto.getBrand());
                    flowDetailVo.setLocation(dto.getStorage());
                    flowDetailVo.setStatus(dto.getStatusDesc() == null ? (e.getRemark() == null ? "旧" : e.getRemark().indexOf("报废") > 0 ? "报废" : "旧") : dto.getStatusDesc());
                    if (flowVo.getAction() != null && flowVo.getAction().equals("8") && flowDetailVo.getRemark().indexOf("易耗品_退库") > -1) {
                        flowDetailVo.setStatus("报废");
                    }
                    flowDetailVo.setTypeDesc(e.getRemark() == null ? null : e.getRemark().indexOf("_") > -1 ? e.getRemark().split("_")[1] : e.getRemark());
                    list.add(flowDetailVo);
                });
            }
        }
        return list;
    }

    @Override
    public void saveFlowKnife(FlowVo flowVo) {
        Map<String, String> dataByDictType = sysDictDataService.getDataByDictType("equipment_ledger_dept");
        String deptName = SecurityUtils.getLoginUser().getUser().getDept().getFactoryName();
        if (dataByDictType != null && deptName != null) {
            flowVo.setDeptName(deptName);
            flowVo.setDeptId(dataByDictType.get(deptName) != null ? Long.parseLong(dataByDictType.get(deptName)) : null);
        }
        flowVo.setCode(IdUtils.getNumber(FlowableCodeEnum.valueOf(flowVo.getMainFlowType()).getValue() + "-", flowMapper.countCurrentDateWithDel() + 1));
        String flowType = flowVo.getMainFlowType().split("_")[0] + "_" + flowVo.getMainFlowType().split("_")[1] + "_" + flowVo.getMainFlowType().split("_")[2];
        //4，新领   5，销售出库 6 调用  7 退库 8 以旧换新
        if ("4".equals(flowVo.getAction()) || "7".equals(flowVo.getAction()) || "8".equals(flowVo.getAction())) {
            // 保存单据
            flowVo.setApprovalStatus(ApprovalDescriptionEnum.B);
            flowVo.setApprovalTime(new Date());
            flowVo.setCreateById(SecurityUtils.getUserId());
            this.save(flowVo);
            flowVo.getDetails().forEach(e -> {
                e.setMainId(flowVo.getId());
                e.setClassType(FlowableCodeEnum.valueOf(flowVo.getMainFlowType()).getClassType());
                e.setExtra(JSONObject.toJSONString(handEqpData(e.getOldJson())));
                flowDetailMapper.insert(e);
            });
        }
        //销售出库 数据验证
        if ("5".equals(flowVo.getAction())) {
            flowVo.setApprovalStatus(ApprovalDescriptionEnum.B);
            flowVo.setApprovalTime(new Date());
            flowVo.setCreateById(SecurityUtils.getUserId());
            this.save(flowVo);
            flowVo.getDetails().forEach(e -> {
                e.setMainId(flowVo.getId());
                e.setClassType(FlowableCodeEnum.valueOf(flowVo.getMainFlowType()).getClassType());
                e.setExtra(JSONObject.toJSONString(handEqpData(e.getOldJson())));
                flowDetailMapper.insert(e);
            });
        }

        //调用主要数据处理 验证
        if ("6".equals(flowVo.getAction())) {
            flowVo.setApprovalStatus(ApprovalDescriptionEnum.B);
            flowVo.setApprovalTime(new Date());
            flowVo.setCreateById(SecurityUtils.getUserId());
            this.save(flowVo);
            flowVo.getDetails().forEach(e -> {
                e.setMainId(flowVo.getId());
                e.setClassType(FlowableCodeEnum.valueOf(flowVo.getMainFlowType()).getClassType());
                JSONObject oldJson = JSONObject.parseObject(e.getOldJson());
                JSONObject dataJson = JSONObject.parseObject(e.getDataJson());
                e.setExtra(JSONObject.toJSONString(handKnifeUseData(oldJson, dataJson, e)));
                flowDetailMapper.insert(e);
            });
        }

    }

    @Override
    public Boolean checkInProcess(Long id, String mainFlowType) {
        List<FlowDetail> list = flowMapper.countFlowByConditon(mainFlowType, Arrays.asList(id));
        if (CollectionUtils.isNotEmpty(list)) {
            return false;
        }
        return true;
    }

    public Boolean checkFlowIds(List<Long> xIds, List<FlowCheck> jIds, FlowVo flowVo) {
        //数据校验
        if (CollectionUtils.isNotEmpty(xIds)) {
            List<FlowCheck> checks = this.getBaseMapper().checkKnife(flowVo.getMainFlowType(), xIds, flowVo.getId());
            if (CollectionUtils.isNotEmpty(checks)) {
                throw new ServiceException(checks.stream().map(e -> e.getName()).collect(Collectors.joining()) + "无法领取,已有审核刀具");
            }
        }
        if (CollectionUtils.isNotEmpty(jIds)) {
            Map<Long, BigDecimal> collect = jIds.stream().collect(Collectors.groupingBy(FlowCheck::getId, Collectors.reducing(BigDecimal.ZERO, FlowCheck::getUseQuantity, BigDecimal::add)));
            List<FlowCheck> flowChecks = this.getBaseMapper().checkKnifeYhp(flowVo.getMainFlowType(), collect.keySet().stream().collect(Collectors.toList()), flowVo.getId());
            if (CollectionUtils.isNotEmpty(flowChecks)) {
                for (FlowCheck flowCheck : flowChecks) {
                    Long id = flowCheck.getId();
                    BigDecimal flowQantity = collect.get(id);
                    if (flowQantity != null) {
                        if (flowCheck.getQuantity().compareTo(flowQantity.add(flowCheck.getUseQuantity())) == -1) {
                            throw new ServiceException(flowCheck.getName() + "无法领取,已有审核刀具");
                        }
                    }
                }
            }
        }
        return false;
    }

    public Boolean checkKnifeMove(List<Long> xIds, List<FlowCheck> jIds, FlowVo flowVo) {
        //数据校验
        if (CollectionUtils.isNotEmpty(xIds)) {
            List<FlowCheck> checks = this.getBaseMapper().checkKnife(flowVo.getMainFlowType(), xIds, flowVo.getId());
            if (CollectionUtils.isNotEmpty(checks)) {
                throw new ServiceException(checks.stream().map(e -> e.getName()).collect(Collectors.joining()) + "无法移库,已有审核刀具");
            }
        }
        if (CollectionUtils.isNotEmpty(jIds)) {
            Map<Long, BigDecimal> collect = jIds.stream().collect(Collectors.groupingBy(FlowCheck::getId, Collectors.reducing(BigDecimal.ZERO, FlowCheck::getUseQuantity, BigDecimal::add)));
            List<FlowCheck> flowChecks = this.getBaseMapper().checkKnifeYhp(flowVo.getMainFlowType(), collect.keySet().stream().collect(Collectors.toList()), flowVo.getId());
            if (CollectionUtils.isNotEmpty(flowChecks)) {
                for (FlowCheck flowCheck : flowChecks) {
                    Long id = flowCheck.getId();
                    BigDecimal flowQantity = collect.get(id);
                    if (flowQantity != null) {
                        if (flowCheck.getQuantity().compareTo(flowQantity.add(flowCheck.getUseQuantity())) == -1) {
                            throw new ServiceException(flowCheck.getName() + "无法移库,已有审核刀具");
                        }
                    }
                }
            }
        }
        return false;
    }

    @Override
    public void editFlow(FlowVo flowVo) {
        // 刀具借用无需编辑直接跳过
        if (flowVo.getMainFlowType().startsWith("flow_re_knife_transfer")) {
            return;
        }
        this.updateById(flowVo);
        if (CollectionUtils.isNotEmpty(flowVo.getDetails()) && StringUtils.isEmpty(flowVo.getNodeName())) {
            if (flowVo.getMainFlowType().startsWith("flow_re_knife")) {
                flowVo.getDetails().forEach(e -> {
                    e.setId(null);
                    e.setClassType(FlowableCodeEnum.valueOf(flowVo.getMainFlowType()).getClassType());
                });
                List<Long> xIds = new ArrayList<>();
                List<FlowCheck> jIds = new ArrayList<>();
                if (flowVo.getMainFlowType().startsWith("flow_re_knife_pick") && flowVo.getAction().equals("4")) {
                    AtomicReference<BigDecimal> quantity = new AtomicReference<>(new BigDecimal(1));
                    //新领取/**/
                    List<FlowDetail> details = new ArrayList<>();
                    flowVo.getDetails().forEach(e -> {
                        JSONObject object = JSONObject.parseObject(e.getDataJson());
                        handleJsonNew(xIds, jIds, details, quantity, e, object);

                    });
                    flowVo.setDetails(details);
                    checkFlowIds(xIds, jIds, flowVo);

                }

                if (flowVo.getMainFlowType().startsWith("flow_re_knife_return") && flowVo.getAction().equals("7")) {
                    AtomicReference<BigDecimal> quantity = new AtomicReference<>(new BigDecimal(1));
                    //新领取/**/
                    List<FlowDetail> details = new ArrayList<>();
                    flowVo.getDetails().forEach(e -> {
                        JSONObject object = JSONObject.parseObject(e.getDataJson());
                        Long sourceId = object.getLong("id");
                        if (object.getString("type").equals("有码刀具")) {
                            FlowDetail flowDetail = new FlowDetail();
                            BeanUtils.copyProperties(e, flowDetail);
                            String status = object.getJSONObject("updateStatusSourceData").getString("dictValue");
                            if ("1".equals(status)) {
                                flowDetail.setRemark("有码_退库_报废");
                            } else {
                                flowDetail.setRemark("有码_退库");
                            }
                            flowDetail.setName(object.getString("name"));
                            flowDetail.setSourceId(sourceId);
                            flowDetail.setQuantity(new BigDecimal(1));
                            flowDetail.setExtra(JSONObject.toJSONString(handData(object, e.getOldJson(), flowVo.getMainFlowType())));
                            details.add(flowDetail);
                        } else {
                            // 拆分数据
                            JSONArray targetLocation = object.getJSONArray("targetLocation");
                            if (targetLocation != null && targetLocation.size() > 0) {
                                for (int i = 0; i < targetLocation.size(); i++) {
                                    FlowDetail flowDetail = new FlowDetail();
                                    BeanUtils.copyProperties(e, flowDetail);
                                    if (i != 0) {
                                        JSONObject jsonObject = JSONObject.parseObject(e.getDataJson());
                                        jsonObject.put("copy", true);
                                        flowDetail.setDataJson(jsonObject.toJSONString());
                                    }
                                    flowDetail.setRemark("易耗品_退库");
                                    flowDetail.setName(object.getString("name"));
                                    flowDetail.setSourceId(sourceId);
                                    FlowDto dto = handData(object, e.getOldJson(), flowVo.getMainFlowType());
                                    JSONObject extra = targetLocation.getJSONObject(i);
                                    Long areaId = extra.getLong("id");
                                    dto.setAreaId(areaId);
                                    flowDetail.setName(extra.getString("name"));
                                    String quantity1 = extra.getString("outCount");
                                    flowDetail.setQuantity(new BigDecimal(quantity1));
                                    flowDetail.setExtra(JSONObject.toJSONString(dto));
                                    details.add(flowDetail);

                                }
                            }
                            Integer scrapCount = object.getInteger("scrapCount");
                            if (CollectionUtils.isEmpty(targetLocation) && (scrapCount == null || scrapCount == 0)) {
                                throw new ServiceException("E01:退库或报废需填写");
                            }
                            if (scrapCount != null && scrapCount > 0) {
                                FlowDetail flowDetail = new FlowDetail();
                                BeanUtils.copyProperties(e, flowDetail);
                                JSONObject jsonObject = JSONObject.parseObject(e.getDataJson());
                                if (targetLocation != null && targetLocation.size() > 0) {
                                    jsonObject.put("copy", true);
                                }
                                flowDetail.setDataJson(jsonObject.toJSONString());
                                flowDetail.setRemark("易耗品_报废");
                                flowDetail.setName(object.getString("name"));
                                flowDetail.setSourceId(sourceId);
                                flowDetail.setQuantity(new BigDecimal(scrapCount));
                                FlowDto dto = handData(object, e.getOldJson(), "3");
                                flowDetail.setExtra(JSONObject.toJSONString(dto));
                                details.add(flowDetail);

                            }
                        }


                    });
                    flowVo.setDetails(details);
                }

                if (flowVo.getMainFlowType().startsWith("flow_re_knife_pick") && flowVo.getAction().equals("8")) {
                    //新领取/**/
                    List<FlowDetail> details = new ArrayList<>();
                    flowVo.getDetails().forEach(e -> {
                        AtomicReference<BigDecimal> quantity = new AtomicReference<>(new BigDecimal(1));
                        JSONObject object = JSONObject.parseObject(e.getDataJson());
                        if (object.getString("feTypeFlag") != null && object.getString("feTypeFlag").equals("replace")) {
                            FlowDetail flowDetail = new FlowDetail();
                            BeanUtils.copyProperties(e, flowDetail);
                            JSONObject jsonObject = JSONObject.parseObject(e.getDataJson());
                            if (object.getJSONObject("lasercode") != null || (object.getJSONArray("targetLocationSourceData") != null && object.getJSONArray("targetLocationSourceData").size() > 0)) {
                                jsonObject.put("copy", true);
                                flowDetail.setDataJson(jsonObject.toJSONString());
                            }
                            Long sourceId = object.getLong("id");
                            if (object.getString("type").equals("有码刀具")) {
                                String status = object.getJSONObject("updateStatusSourceData").getString("dictValue");
                                if ("1".equals(status)) {
                                    flowDetail.setRemark("有码_退库_报废");
                                    jsonObject.remove("returnLocation");
                                    object.remove("returnLocation");
                                    e.setDataJson(object.toJSONString());
                                } else {
                                    flowDetail.setRemark("有码_退库");
                                }
                                quantity.set(BigDecimal.valueOf(1));
                                flowDetail.setExtra(JSONObject.toJSONString(handData(object, e.getOldJson(), "2")));
                            } else {
                                quantity.set(new BigDecimal(object.getString("returnCount")));
                                flowDetail.setRemark("易耗品_退库");
                                jsonObject.remove("returnLocation");
                                object.remove("returnLocation");
                                e.setDataJson(object.toJSONString());
                                flowDetail.setDataJson(jsonObject.toJSONString());
                                flowDetail.setExtra(JSONObject.toJSONString(handData(object, e.getOldJson(), flowVo.getMainFlowType())));
                            }
                            flowDetail.setSourceId(sourceId);
                            flowDetail.setName(object.getString("name"));
                            flowDetail.setQuantity(quantity.get());

                            if (CollectionUtils.isNotEmpty(details)) {
                                String code = object.getString("code");
                                if (StringUtils.isNotEmpty(code)) {
                                    if (details.stream().filter(k -> code.equals(JSONUtil.toBean(k.getExtra(), FlowDto.class).getCode())).count() == 0) {
                                        details.add(flowDetail);
                                    }
                                } else {
                                    details.add(flowDetail);
                                }

                            } else {
                                details.add(flowDetail);
                            }

                            handleJsonNew(xIds, jIds, details, quantity, e, object);
                        } else {
                            handleJsonNew(xIds, jIds, details, quantity, e, object);
                        }
                        checkFlowIds(xIds, jIds, flowVo);
                    });

                    flowVo.setDetails(details);
                }
            } else {
                flowVo.getDetails().forEach(e -> {
                    e.setClassType(FlowableCodeEnum.valueOf(flowVo.getMainFlowType()).getClassType());
                });
            }

        }
        cleanDetailsData(flowVo.getId(), flowVo.getDetails(), FlowDetail.class);

    }

    @Override
    public Page<FlowVo> pageVo(Page<FlowVo> page, QueryWrapper<FlowQuery> queryWrapper) {
        Page<FlowVo> flowVoPage = flowMapper.selectVo(page, queryWrapper);
        if (CollectionUtils.isNotEmpty(flowVoPage.getRecords())) {
            flowVoPage.getRecords().forEach(e -> {
                if (e.getExtra() != null) {
                    FlowDto dto = JSONUtil.toBean(e.getExtra(), FlowDto.class);
                    e.setEqpName(dto.getEqpName());
                    e.setEqpNumber(dto.getEqpNumber());
                    if (CollUtil.isNotEmpty(dto.getProjects())) {
                        e.setProjects(dto.getProjects().toString());
                    }
                }
            });


        }
        return flowVoPage;
    }

    @Override
    public Page<FlowVo> pageVoCommon(Page<FlowVo> page, QueryWrapper<FlowQuery> queryWrapper) {
        return flowMapper.selectVo(page, queryWrapper);
    }

    @Override
    public Page<FlowDetailVo> pageVoNew(Page<FlowVo> page, QueryWrapper<FlowQuery> queryWrapper) {
        Page<FlowDetailVo> flowVoPage = flowMapper.selectVoNew(page, queryWrapper);
        if (CollectionUtils.isNotEmpty(flowVoPage.getRecords())) {
            flowVoPage.getRecords().forEach(e -> {
                FlowDto dto = new FlowDto();
                if (e.getExtra() != null) {
                    dto = JSONUtil.toBean(e.getExtra(), FlowDto.class);
                    e.getFlow().setEqpName(dto.getEqpName());
                    e.getFlow().setEqpNumber(dto.getEqpNumber());
                    e.getFlow().setProjects(dto.getProjects() == null ? "" : dto.getProjects().toString());
                    e.setFactoryArea(dto.getFactoryArea());
                    e.setEqpNumber(dto.getEqpNumber());
                    e.setShortName(dto.getShortName());
                }
                if (StringUtils.isNotEmpty(e.getOldJson())) {
                    JSONObject jsonObject = JSONObject.parseObject(e.getOldJson());
                    JSONArray projectMachines = jsonObject.getJSONArray("projectMachines");
                    Set<String> projectNames = new HashSet<>();
                    if (projectMachines != null && projectMachines.size() > 0) {
                        for (int i = 0; i < projectMachines.size(); i++) {
                            projectNames.add(projectMachines.getJSONObject(i).getString("projectName"));
                        }
                    }
                    e.setProjectName(projectNames.stream().collect(Collectors.joining(",")));
                }

                e.setDataJson(null);
                e.setOldJson(null);
                e.getFlow().setDetails(null);
                e.setSpec(dto.getSpec());
                e.setName(dto.getName());
                e.setCode(dto.getCode());
                e.setNumber(dto.getNumber());
                e.setUnit(dto.getUnit());
                e.setBrand(dto.getBrand());
                e.setLocation(dto.getStorage());
                e.setOldQuantity(dto.getOldQuantity());
                e.setStatus(dto.getStatusDesc() == null ? (e.getRemark() == null ? "旧" : e.getRemark().indexOf("报废") > 0 ? "报废" : "旧") : dto.getStatusDesc());
                e.setTypeDesc(e.getRemark() == null ? null : e.getRemark().indexOf("_") > -1 ? e.getRemark().split("_")[1] : e.getRemark());
            });
        }
        return flowVoPage;
    }

    @Override
    @Transactional
    @PlugAnn(groupClass = FlowablModelApproval.Approval.class)
    public AjaxResult commitFlow(@PlugParam FlowVo flowVo, @PlugParam String mainFlowType, @PlugParam Long userId,
                                 @PlugParam Long deptId, @PlugParam String nickName, @PlugParam String deptName, String extra) {

        flowVo.setMainFlowType(mainFlowType);
        flowVo.setFlowType(mainFlowType);
        flowVo.setCreateById(userId);
        flowVo.setCode(IdUtils.getNumber(FlowableCodeEnum.valueOf(flowVo.getMainFlowType()).getValue() + "-", flowMapper.countCurrentDateWithDel() + 1));
        flowVo.setApprovalStatus(ApprovalDescriptionEnum.B);
        flowVo.setApprovalTime(new Date());
        flowVo.setCreateById(SecurityUtils.getUserId());
        flowVo.setDeptId(SecurityUtils.getDeptId());
        flowVo.setDeptName(SecurityUtils.getDeptName());

        //校验单据是否发起审核
        JSONObject jsonObject = JSONObject.parseObject(extra);
        replaceType(jsonObject);
        flowVo.setQksm(jsonObject.toJSONString());
        this.save(flowVo);
        FlowDto dto = new FlowDto();

        return AjaxResult.success();
    }


    public void replaceType(JSONObject json) {
        Set<Map.Entry<String, Object>> keySet = json.entrySet();
        Iterator<Map.Entry<String, Object>> iterator = keySet.iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> next = iterator.next();
            if (next.getValue() instanceof JSONObject) {
                replaceType((JSONObject) next.getValue());
            } else if (next.getValue() instanceof JSONArray) {
                ((JSONArray) next.getValue()).forEach(v -> {
                    if (v instanceof JSONObject) {
                        replaceType((JSONObject) v);
                    } else if (v instanceof Long) {
                        json.put(next.getKey(), v.toString());
                    }
                });
            } else if (next.getValue() instanceof Long) {
                json.put(next.getKey(), next.getValue().toString());
            }
        }
    }


    @Override
    @Transactional
    @PlugAnn(groupClass = FlowablModelApproval.Approval.class)
    public AjaxResult commitFlow(@PlugParam List<Long> ids, @PlugParam String mainFlowType, @PlugParam Long userId,
                                 @PlugParam Long deptId, @PlugParam String nickName, @PlugParam String deptName) {

        for (Long id : ids) {
            FlowVo flowVo = new FlowVo();
            flowVo.setId(id);
            flowVo.setMainFlowType(mainFlowType);
            flowVo.setFlowType(mainFlowType);
            flowVo.setCreateById(userId);
            //flowVo.setCode(IdUtils.getNumber(FlowableCodeEnum.valueOf(flowVo.getMainFlowType()).getValue() + "-", flowMapper.countCurrentDateWithDel() + 1));
            flowVo.setApprovalStatus(ApprovalDescriptionEnum.B);
            flowVo.setApprovalTime(new Date());
            flowVo.setCreateById(SecurityUtils.getUserId());
            //校验单据是否发起审核

            this.updateById(flowVo);
        }
        return AjaxResult.success();
    }





    @Override
    public void dealFlow(FlowVo flowVo) {
        if (flowVo.getId() == null) {
            if (CollectionUtils.isNotEmpty(flowVo.getDetails())) {
                String projectNos = flowVo.getDetails().stream().map(e -> e.getName()).distinct().collect(Collectors.joining(","));
                flowVo.setReason(projectNos);
            }

            flowVo.setCode(IdUtils.getNumber(FlowableCodeEnum.valueOf(flowVo.getFlowType()).getValue() + "-", flowMapper.countCurrentDateWithDel() + 1));
            flowVo.setFlowType(flowVo.getFlowType());
            flowVo.setMainFlowType(flowVo.getFlowType());
            flowVo.setCreateById(SecurityUtils.getUserId());
            flowVo.setAction(flowVo.getExceptionValue());

            this.flowMapper.insert(flowVo);
            if (CollectionUtils.isNotEmpty(flowVo.getDetails())) {
                for (FlowDetail detail : flowVo.getDetails()) {
                    detail.setMainId(flowVo.getId());
                    detail.setSpec(detail.getContent());
                    detail.setExtra(detail.getContentType());
                    this.flowDetailMapper.insert(detail);
                }
            }

        } else {
            if (CollectionUtils.isNotEmpty(flowVo.getDetails())) {
                if (!"flow_re_knife_move".equals(flowVo.getMainFlowType())) {
                    for (FlowDetail detail : flowVo.getDetails()) {
                        cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(detail.getDataJson());
                        detail.setSpec(jsonObject.get("content").toString());
                        detail.setExtra(jsonObject.get("type").toString());
                    }
                    String projectNos = flowVo.getDetails().stream().map(e -> e.getName()).distinct().collect(Collectors.joining(","));
                    flowVo.setReason(projectNos);
                    flowVo.setAction(flowVo.getExceptionValue());
                }

            }
            if ("flow_re_knife_move".equals(flowVo.getMainFlowType())) {
                JSONObject jsonObject = JSONObject.parseObject(flowVo.getQksm());
                replaceType(jsonObject);
                flowVo.setQksm(jsonObject.toJSONString());
            }
            this.flowMapper.updateById(flowVo);
            cleanDetailsData(flowVo.getId(), flowVo.getDetails(), FlowDetail.class);
        }
        storageService.initFileClass(flowVo.getId(), flowVo.getFlowType(), flowVo.getFiles());
    }

    @Override
    public void checkFlow(FlowVo flowVo) {

        //检验是否审核过
        String sql = flowVo.getDetails().stream().map((i) -> {
            return String.format("(%s,%s,%s)", i.getSourceId(), i.getName(), i.getSpec());
        }).collect(Collectors.joining(","));
        List<FlowDetail> detailList = flowDetailMapper.selectList(new LambdaQueryWrapper<FlowDetail>().apply
                ("(source_id,name,spec) in (" + sql + ")"));
        if (detailList.size() > 0) {
            List<Flow> list = this.list(new LambdaQueryWrapper<Flow>().in(Flow::getApprovalStatus, Arrays.asList("B", "C")).in(Flow::getId, detailList.stream().map(e -> e.getMainId()).collect(Collectors.toList())));
            if (CollectionUtils.isNotEmpty(list)) {
                throw new ServiceException(String.format("%s已提交审核", detailList.stream().map(e -> e.getRemark() + " " + e.getSpec() + " " + e.getName()).collect(Collectors.joining(","))));
            }
        }
    }


    private void handleJsonNew(List<Long> xids, List<FlowCheck> jIds, List<FlowDetail> details, AtomicReference<BigDecimal> quantity, FlowDetail e, JSONObject object) {
        if (object.getString("type").equals("有码刀具")) {
            FlowDetail flowDetail = new FlowDetail();
            BeanUtils.copyProperties(e, flowDetail);
            if (object.getJSONObject("lasercode") != null) {
                Long sourceId = object.getJSONObject("lasercode").getJSONObject("extra").getLong("id");
                flowDetail.setRemark("新领");
                flowDetail.setName(object.getJSONObject("lasercode").getJSONObject("extra").getString("name"));
                if (CollectionUtils.isNotEmpty(xids) && xids.contains(sourceId)) {
                    throw new ServiceException("存在" + flowDetail.getName() + "相同的有码刀具");
                }
                quantity.set(BigDecimal.valueOf(1));
                xids.add(sourceId);
                flowDetail.setSourceId(sourceId);
                flowDetail.setQuantity(quantity.get());
                flowDetail.setExtra(JSONObject.toJSONString(handData(object.getJSONObject("lasercode").getJSONObject("extra"), e.getOldJson(), "1")));
                details.add(flowDetail);
            }
        } else {
            JSONArray targetLocationSourceData = object.getJSONArray("targetLocationSourceData");
            if (targetLocationSourceData != null && targetLocationSourceData.size() > 0) {
                for (int i = 0; i < targetLocationSourceData.size(); i++) {
                    FlowDetail flowDetail = new FlowDetail();
                    BeanUtils.copyProperties(e, flowDetail);
                    if (i != 0) {
                        JSONObject jsonObject = JSONObject.parseObject(e.getDataJson());
                        jsonObject.put("copy", true);
                        flowDetail.setDataJson(jsonObject.toJSONString());
                    }
                    JSONObject extra = targetLocationSourceData.getJSONObject(i).getJSONObject("extra");
                    Long sourceId = extra.getLong("id");
                    flowDetail.setName(extra.getString("name"));
                    String quantity1 = targetLocationSourceData.getJSONObject(i).getString("outCount");
                    quantity.set(new BigDecimal(quantity1));
                    FlowCheck flowCheck = new FlowCheck();
                    flowCheck.setId(sourceId);
                    flowCheck.setName(extra.getString("name"));
                    flowCheck.setUseQuantity(quantity.get());
                    jIds.add(flowCheck);
                    flowDetail.setRemark("易耗品_新领");
                    flowDetail.setSourceId(sourceId);
                    flowDetail.setQuantity(quantity.get());
                    flowDetail.setExtra(JSONObject.toJSONString(handData(extra, e.getOldJson(), "1")));
                    details.add(flowDetail);
                }
            }
        }

    }


    public FlowDto handData(JSONObject object, String oldJson, String type) {
        FlowDto dto = new FlowDto();
        JSONObject jsonObject = JSONObject.parseObject(oldJson);
        dto.setBrand(object.getString("brand"));
        dto.setSpec(object.getString("spec"));
        dto.setName(object.getString("name"));
        dto.setNumber(object.getString("number"));
        dto.setUnit(object.getString("unit"));
        dto.setType(object.getString("type"));
        dto.setEqpNumber(jsonObject.getJSONObject("equipment").getString("number"));
        dto.setEquipmentLedgerId(jsonObject.getJSONObject("equipment").getLong("id"));
        dto.setEqpName(jsonObject.getJSONObject("equipment").getString("eqpName"));
        dto.setShortName(jsonObject.getJSONObject("equipment").getString("remark"));
        dto.setStatusDesc(object.getString("statusName"));
        dto.setCode(object.getString("code"));
        dto.setStorage(object.getString("location"));
        if (object.getString("knifeArea") != null) {
            dto.setFactoryArea(object.getString("knifeArea"));
        } else {
            dto.setFactoryArea(object.getString("factoryArea"));
        }
        //CommonClassify commonclassify = commonClassifyService.getOne(new LambdaQueryWrapper<CommonClassify>().eq(CommonClassify::getName, dto.getFactoryArea()).eq(CommonClassify::getClassifyType, "knifeArea").eq(CommonClassify::getParentClassifyId, 0));
        //dto.setFactoryAreaId(commonclassify.getId());
        if (type.equals("flow_re_knife_return")) {
            if (object.getJSONObject("updateStatusSourceData") != null) {
                String status = object.getJSONObject("updateStatusSourceData").getString("dictValue");
                if (!status.equals("1")) {
                    dto.setAreaId(object.getJSONArray("targetLocation").getJSONObject(0).getLong("id"));
                    dto.setLocation(object.getJSONArray("targetLocation").getJSONObject(0).getString("fullLocation"));
                    dto.setStorage(object.getJSONArray("targetLocation").getJSONObject(0).getString("fullLocation"));
                    dto.setFactoryAreaId(object.getJSONArray("targetLocation").getJSONObject(0).getLong("topClassifyId"));
                    dto.setStatus(status);
                    dto.setStatusDesc(object.getJSONObject("updateStatusSourceData").getString("dictLabel"));
                } else {
                    dto.setStatus(status);
                    dto.setStatusDesc(object.getJSONObject("updateStatusSourceData").getString("dictLabel"));
                }
            } else {
                if (object.getJSONArray("targetLocation") != null) {
                    dto.setFactoryAreaId(object.getJSONArray("targetLocation").getJSONObject(0).getLong("topClassifyId"));
                }
            }
        } else if (type.equals("2")) {
            //以旧换新，有码刀具退库
            String status = object.getJSONObject("updateStatusSourceData").getString("dictValue");
            if (!status.equals("1")) {
                if (object.getJSONArray("returnLocation") != null && object.getJSONArray("returnLocation").getJSONObject(0) != null) {
                    dto.setAreaId(object.getJSONArray("returnLocation").getJSONObject(0).getLong("id"));
                    dto.setLocation(object.getJSONArray("returnLocation").getJSONObject(0).getString("fullLocation"));
                    dto.setStorage(object.getJSONArray("returnLocation").getJSONObject(0).getString("fullLocation"));
                    dto.setFactoryAreaId(object.getJSONArray("returnLocation").getJSONObject(0).getLong("topClassifyId"));
                } else {
                    dto.setAreaId(object.getJSONObject("targetLocation1").getLong("id"));
                    dto.setLocation(object.getJSONObject("targetLocation1").getString("fullLocation"));
                    dto.setStorage(object.getJSONObject("targetLocation1").getString("fullLocation"));
                    dto.setFactoryAreaId(object.getJSONObject("targetLocation1").getLong("topClassifyId"));
                }
                dto.setStatus(status);
                dto.setStatusDesc(object.getJSONObject("updateStatusSourceData").getString("dictLabel"));
            } else {
                dto.setStatus(status);
                dto.setStatusDesc(object.getJSONObject("updateStatusSourceData").getString("dictLabel"));
            }

        }
        JSONArray projectMachines = jsonObject.getJSONArray("projectMachines");
        List<String> projects = new ArrayList<>();
        for (int i = 0; i < projectMachines.size(); i++) {
            projects.add(projectMachines.getJSONObject(i).getString("projectMachineNo"));
        }
        dto.setProjects(projects);
        return dto;
    }


    public FlowDto handKnifeUseData(JSONObject oldJson, JSONObject dataJson, FlowDetail detail) {
        FlowDto dto = new FlowDto();

        // 借出设备
        dto.setLendEqpNumber(oldJson.getJSONObject("equipment").getString("number"));
        dto.setLendEquipmentLedgerId(oldJson.getJSONObject("equipment").getLong("id"));
        dto.setLendEqpName(oldJson.getJSONObject("equipment").getString("eqpName"));


        // 借入设备和人
        Long equipmentLedgerId = dataJson.getLong("borrowerEquipmentLedgerId");
        dto.setEqpNumber(dataJson.getString("borrowerEqpNumber"));
        dto.setEquipmentLedgerId(equipmentLedgerId);
        dto.setEqpName(dataJson.getString("borrowerEqpName"));
        dto.setEqpNumber(dataJson.getString("borrowerEqpNumber"));

        dto.setBorrowerUserId(dataJson.getLong("borrowerUserId"));
        dto.setBorrowerUserName(dataJson.getString("borrowerUserName"));
        dto.setCode(dataJson.getString("code"));
        dto.setNumber(dataJson.getString("number"));
        dto.setBrand(dataJson.getString("brand"));
        dto.setSpec(dataJson.getString("spec"));

        dto.setFactoryArea(dataJson.getString("factoryArea"));
        String name = dataJson.getString("name");
        dto.setName(name);
//        String type = dataJson.getString("type");
        String quantity1 = dataJson.getString("quantity");
        BigDecimal quantity = new BigDecimal(quantity1);
        detail.setQuantity(quantity);
        detail.setRemark("借用");
        detail.setName(name);
        dto.setQuantity(quantity);
        dto.setKnifeUseId(dataJson.getLong("id"));
        return dto;
    }

    public FlowDto handEqpData(String oldJson) {
        FlowDto dto = new FlowDto();
        JSONObject jsonObject = JSONObject.parseObject(oldJson);

        dto.setEqpNumber(jsonObject.getJSONObject("equipment").getString("number"));
        dto.setEquipmentLedgerId(jsonObject.getJSONObject("equipment").getLong("id"));
        dto.setEqpName(jsonObject.getJSONObject("equipment").getString("eqpName"));
        dto.setShortName(jsonObject.getJSONObject("equipment").getString("remark"));
        JSONArray projectMachines = jsonObject.getJSONArray("projectMachines");
        List<String> projects = new ArrayList<>();
        for (int i = 0; i < projectMachines.size(); i++) {
            projects.add(projectMachines.getJSONObject(i).getString("projectMachineNo"));
        }
        dto.setProjects(projects);
        return dto;
    }

}
